home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / hypercrd / hc2_x / regnpckg.sit / BitMapToRegion ƒ / BitMapRgn.c next >
Text File  |  1990-12-10  |  10KB  |  329 lines

  1. /*
  2. >>    BitMapRgn.c, June 90                                                <<
  3. >>                                                                        <<
  4. >>  Nigel Perry, np@doc.ic.ac.uk                                        <<
  5. >>  Dept of Computing, Imperial College, 180 Queens Gate,               <<
  6. >>  London SW7 2BZ, England                                             <<
  7. >>                                                                        <<
  8. >>    Version of the BitMapRgn trap (0xA8D7) which is not in all systems  <<
  9. >>  This C/asm version is an extension of a C routine written           <<
  10. >>    by Juri Munkki in April 89. Added error checks, now works with a    <<
  11. >>  BitMap with any origin, used assembler for speed                    <<
  12. >>                                                                         <<
  13. >>    Juri Munkki, jmunkki@kampi.hut.fi                                    <<
  14. >>    Helsinki University of Technology Computing Centre                    <<
  15. >>    Otakaari 1 U044B, SF02150 Espoo, Finland                            <<
  16. >>                                                                        <<
  17. >>    This program is in the PUBLIC DOMAIN.                                <<
  18. */
  19.  
  20. /* Define TRAPATCH if trap patch version (project BMTR Trap ╣).
  21.    Will compile a TRAP resource and write it to BMTR XCMD ╣.rsrc,
  22.    to use in the BMTR Patcher.╣ & BMTR Init.╣ this TRAP resource must be
  23.    copied with ResEdit to the appropriate ╣.rsrc file. DO NOT change this
  24.    project to write directly to another ╣.rsrc file, they contain other
  25.    resources which you will DESTROY.
  26.  */
  27. #define TRAPATCH
  28.  
  29. #include <asm.h>
  30. #define _BitMapToRegion                 0xA8D7
  31. #define _Unimplemented                    0xA89F
  32.  
  33. #define rgnTooBigErr -500
  34.  
  35. #ifdef TRAPATCH
  36. #define BitMapRgn main
  37. /* CODE header */
  38. header()
  39. {    extern pascal OSErr BitMapRgn();
  40.  
  41.     asm
  42.     {    bra.s    @1                ; header
  43.         dc.b    'n','p','9','0'    ; header + 2
  44.         dc.b    'j','u','r','i'    ; header + 6
  45.     @1:    jmp        BitMapRgn
  46.     }
  47. }
  48. #endif TRAPATCH
  49.  
  50. /*
  51. >>    Convert a bitmap into a region.
  52. */
  53. pascal OSErr BitMapRgn(RgnHandle, BitMap *);
  54. pascal OSErr BitMapRgn(Target, Bits)
  55. RgnHandle    Target;
  56. BitMap        *Bits;
  57. {    int                *TargetBase;        /* StripAddress(*Target) */
  58.     int                *RowStart;            /* Index of first x value on row */
  59.     int                TargetSize,RgnSize;    /* Size in data words & bytes */
  60.     Rect            TempRect,RgnBounds;    /* Temporary & region bounds rects */
  61.     BitMap            RowBitMap;            /* Working bitmap with one row in it */
  62.     int                i;                    /* Row counter in a "for" loop */
  63.     int                diff;
  64.     int                left;
  65.     /* three address registers a2-4 */
  66.     register int    *TargetP;            /* Pointer to region data array */
  67.     register int    *MaxTarget;            /* Memory management stuff */
  68. #ifndef TRAPATCH
  69.     register long    *BitP;                /* Pointer to current line */
  70. #else
  71.     /* need to force a4 in LSC CODE resource */
  72. #define BitP a4
  73. #endif
  74.     /* five data registers d3-7 */
  75.     register int    shiftcount;            /* shift count for BitWord */
  76.     register long    BitWord;            /* current 32 bits of line */
  77.     register int    x;                    /* Column counter in a "for" loop */
  78.     register int    pixelstatus;        /* Flag is false if last pixel is white */
  79.     register int    right;
  80.     
  81. #ifdef TRAPATCH
  82.     /* save a4 in patch */
  83.     asm
  84.     {    move.l    a4,-(a7)
  85.     }
  86. #endif
  87.     asm
  88.     {    move.l    #4096,d0        /* Initial guess for final region size */
  89.         move.w    d0,TargetSize
  90.         move.l    Target,a0        /* Allocate initial data buffer */
  91.         _SetHandleSize
  92.         bne        @bomb            /* Did we run out of RAM? 0=failure. */
  93.         _HLock                    /* HLock((Handle)Target); */
  94.     
  95.         /* TargetP points to region data */
  96.         move.l    Target,a0        /* TargetBase = StripAddres(*(Handle)Target) */
  97.         move.l    (a0),d0
  98.         _StripAddress
  99.         move.l    d0,a0
  100.         move.l    d0,TargetBase
  101.         lea        10(a0),TargetP    /* TargetP = (TargetBase + 10); */
  102.         /* A safe maximum value for our index */
  103.         move.w    TargetSize,d0
  104.         lea        -8(a0,d0.w),MaxTarget    /* MaxTarget = TargetBase + TargetSize - 8; */
  105.  
  106.         /*    Set region bounds to nothing: */
  107.         move.l    #0x7FFF7FFF,RgnBounds.top    /* SetRect(&RgnBounds,32767,32767,-32767,-32767); */
  108.         move.l    #0x80018001,RgnBounds.bottom
  109.     
  110.         /*    Set up a bitmap with a single line: */
  111.         move.l    Bits,a0
  112.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,left)(a0),TempRect.left    /* Set up left & right bounds */
  113.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,right)(a0),TempRect.right
  114.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,top)(a0),d0
  115.         move.w    d0,TempRect.top;        /* Single row bitmap with height = 1 */
  116.         addq.w    #1,d0
  117.         move.w    d0,TempRect.bottom
  118.         move.l    TempRect.top,RowBitMap.bounds.top    /* RowBitMap.bounds=TempRect; */
  119.         move.l    TempRect.bottom,RowBitMap.bounds.bottom;
  120.         moveq    #15,d0                /* RowBitMap.rowBytes = ((TempRect.width + 15) >> 4) << 1; */
  121.         add.w    TempRect.right,d0
  122.         sub.w    TempRect.left,d0
  123.         asr.w    #4,d0
  124.         asl.w    #1,d0
  125.         move.w    d0,RowBitMap.rowBytes
  126.         ext.w    d0                    /* RowBitMap.baseAddr = NewPtr(RowBitMap.rowBytes); */
  127.         _NewPtr
  128.         bne        @bomb
  129.         move.l    a0,RowBitMap.baseAddr
  130.     }
  131.  
  132.     /*    Start out with the first line of the source bitmap */
  133.     CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcCopy,0);
  134.     
  135.     asm
  136.     {    /* right = Bits->bounds.right; */
  137.         move.l    Bits,a0
  138.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,right)(a0),right
  139.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,left)(a0),left
  140.         /* i = Bits->bounds.bottom - Bits->bounds.top; */
  141.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,bottom)(a0),d0
  142.         sub.w    OFFSET(BitMap,bounds)+OFFSET(Rect,top)(a0),d0
  143.         move.w    d0,i
  144.     }
  145.     
  146.     for(; i >= 0; i--)    /* For every line and more */
  147.     {    /*    Row data starts with Y value*/
  148.         asm
  149.         {    move.w    TempRect.top,(TargetP)+    /* *TargetP++ = TempRect.top; */
  150.         }
  151.         RowStart = TargetP;                    /* X values on row start here */
  152.         pixelstatus = 0;                    /* Pixels outside bitmap are white */
  153.         
  154.         asm
  155.         {    move.l    RowBitMap.baseAddr,BitP    /* BitP = (long *)RowBitMap.baseAddr; */
  156.         }
  157.         shiftcount = 0;
  158.         for(x = left; x<right; x++)
  159.         {    asm
  160.             {    tst.w    shiftcount
  161.                 bne.s    @nextBit
  162.                 moveq    #32,shiftcount
  163.                 move.l    (BitP)+,BitWord            /* BitWord = *BitP++; */
  164.             @nextBit
  165.                 subq.w    #1,shiftcount
  166.                 /* Test for a change */
  167.                 /* if((BitTst(RowBitMap.baseAddr,x)!=0) != pixelstatus) */
  168.                 lsl.l    #1,BitWord
  169.                 scs        d0
  170.                 eor.b    pixelstatus,d0
  171.                 beq        @elselab
  172.             }
  173.             {    asm
  174.                 {    /* Color changed */
  175.                     not.b    pixelstatus            /* pixelstatus = !pixelstatus; */
  176.                     /*    Record x coordinate    */
  177.                     move.w    x,(TargetP)+        /* *TargetP++ = x; */
  178.                 }
  179.                 if(TargetP >= MaxTarget)        /* Is the buffer full? */
  180.                 {    asm
  181.                     {    move.l    TargetP,d0        /* diff = TargetP - TargetBase; */
  182.                         sub.l    TargetBase,d0
  183.                         move.w    d0,diff
  184.                         add.w    #2048,TargetSize    /* Enlarge the buffer */ 
  185.                         bvc.s    @sizeOk                /* if((TargetSize+=2048) > 32767) */
  186.                         move.w    #rgnTooBigErr,d0
  187.                         bra        @bomb2
  188.                     @sizeOk
  189.                         move.l    Target,a0        /* Unlock to change size */
  190.                         _HUnlock
  191.                         move.w    TargetSize,d0    /* Change the size */
  192.                         ext.l    d0
  193.                         _SetHandleSize
  194.                         bne        @bomb2            /* No success? */
  195.                         _HLock                    /* Lock it again */
  196.                     
  197.                         move.l    Target,a0        /* TargetBase = StripAddress(*(Handle)Target); */
  198.                         move.l    (a0),d0
  199.                         _StripAddress
  200.                         move.l    d0,TargetBase
  201.                         move.l    d0,TargetP
  202.                         adda.w    diff,TargetP    /* TargetP = TargetBase + diff; */
  203.                         /* New maximum index */
  204.                         subq.l    #8,d0
  205.                         move.l    d0,MaxTarget    /* MaxTarget= TargetBase + TargetSize; */
  206.                         adda.w    TargetSize,MaxTarget
  207.                     }
  208.                 }
  209.             }
  210.         elselab:
  211.             ;
  212.         }
  213.         if(pixelstatus) /*    Last pixel was black, record edge    */
  214.             asm
  215.             {    move.w    x,(TargetP)+            /* *TargetP++=x; */
  216.             }
  217.         if(RowStart==TargetP)                    /*    Row was empty (no changes) */
  218.             TargetP--;                            /*    Remove Y value from data */
  219.         else
  220.         {    /*    Check for new region bounds: */
  221.             asm
  222.             {    move.l    RowStart,a0            /* if(*RowStart < RgnBounds.left) */
  223.                 move.w    (a0),d0
  224.                 cmp.w    RgnBounds.left,d0
  225.                 bge.s    @else1
  226.                 move.w    d0,RgnBounds.left    /* RgnBounds.left = *RowStart; */
  227.             @else1
  228.                 move.w    -2(TargetP),d0        /* if(TargetP[-1] > RgnBounds.right) */
  229.                 cmp.w    RgnBounds.right,d0
  230.                 ble.s    @else2
  231.                 move.w    d0,RgnBounds.right    /* RgnBounds.right = TargetP[-1]; */
  232.             @else2
  233.             }
  234.             
  235.             RgnBounds.bottom = TempRect.top;
  236.  
  237.             /* Write an "end of line" flag */
  238.             asm
  239.             {    move.w    #32767,(TargetP)+        /* *TargetP++ = 32767; */
  240.             }
  241.         }
  242.  
  243.         /*    Copy current line into the single line bitmap: */
  244.         if(i>0) CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcCopy,0);
  245.  
  246.         TempRect.top++; TempRect.bottom++;            /*    Move one line down            */
  247.         
  248.         /*    If we are still inside the bitmap, XOR this line with the previous line:*/
  249.         if(i>1)    CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcXor,0);
  250.     }
  251.  
  252.     /* RgnBounds.top = TargetBase[5]; */    /* Top boundary is first recorded Y coordinate */
  253.     asm
  254.     {    move.l    TargetBase,a0    ; (*)
  255.         move.w    10(a0),RgnBounds.top
  256.     }
  257.  
  258.     /*    If the region is empty, set the bounds rect to an empty rectangle: */
  259.     if(RgnBounds.right<=RgnBounds.left || RgnBounds.bottom<=RgnBounds.top)
  260.         asm
  261.         {    clr.l    RgnBounds.top        /* SetRect(&RgnBounds,0,0,0,0); */
  262.             clr.l    RgnBounds.bottom
  263.         }
  264.  
  265.     asm
  266.     {    /*    Write an "end of region" flag */
  267.         move.w    #32767,(TargetP)+        /* *TargetP++ = 32767; */
  268.     
  269.         /*    Calculate region size.*/
  270.         move.l    TargetP,d0        /* RgnSize = (TargetP - TargetBase) * 2; */
  271.         ; sub.l    TargetBase,d0    /* result must be <= 32767 */
  272.         sub.l    a0,d0    ; TargetBase is in a0 (*)
  273.         cmp.w    #28,d0            /* if(RgnSize<=28) RgnSize=10; */
  274.         bgt.s    @3
  275.         moveq    #10,d0            /* Rectangular or empty region is only a Rect */
  276.     @3:    move.w    d0,RgnSize    ; (**)
  277.     
  278.         /* Store region bounds rectangle */
  279.         /* ((RgnPtr)TargetBase)->rgnBBox=RgnBounds; */
  280.         ; move.l    TargetBase,a0 already in a0 (*)
  281.         move.l    RgnBounds.top,OFFSET(Region,rgnBBox)+OFFSET(Rect,top)(a0)
  282.         move.l    RgnBounds.bottom,OFFSET(Region,rgnBBox)+OFFSET(Rect,bottom)(a0)
  283.         /* Store region size (low 16 bits) */
  284.         /* ((RgnPtr)TargetBase)->rgnSize=RgnSize; */
  285.         move.w    d0,OFFSET(Region,rgnSize)(a0)    ; RgnSize is in d0 (**)
  286.     }
  287.     
  288.     
  289.  
  290.     asm
  291.     {    /*    Unlock our target region. */
  292.         move.l    Target,a0        /* HUnlock((Handle)Target);    */
  293.         _HUnlock
  294.         
  295.         /*    Resize region to optimally small */
  296.         move.w    RgnSize,d0
  297.         ext.l    d0
  298.         _SetHandleSize            /* SetHandleSize((Handle)Target,RgnSize); */
  299.         bne.s    @bomb2            /* shouldn't occur... */
  300.     }
  301.  
  302.     asm
  303.     {    move.l    RowBitMap.baseAddr,a0    /* DisposPtr(RowBitMap.baseAddr) */
  304.         _DisposPtr
  305.         bne.s    @bomb
  306.         bra.s    @done                    /* return noErr */
  307. bomb2:
  308.         move.w    d0,-(a7)
  309.         move.l    RowBitMap.baseAddr,a0
  310.         _DisposPtr
  311.         bra.s    @bomb3
  312. bomb:
  313.         move.w    d0,-(a7)
  314. bomb3:
  315.         move.l    Target,a0
  316.         move.l    a0,-(a7)
  317.         _HUnlock                        /* may still be locked */
  318.         _SetEmptyRgn
  319.         move.w    (a7)+,d0
  320.         
  321. done:
  322. #ifdef TRAPATCH
  323.         ; get a4 back
  324.         move.l    (a7)+,a4
  325. #endif
  326.  
  327.     }
  328.  
  329. }